import React, {
  useState,
  useEffect,
  useContext,
  useReducer,
  useCallback,
  useMemo,
  useRef,
  useImperativeHandle,
  useLayoutEffect,
  useDebugValue,
  useDeferredValue,
  useTransition,
  useId,
  useSyncExternalStore,
  useInsertionEffect,
} from "react";
import type { InputRef } from "antd";
import { Collapse, Button, Input, Divider, Typography, Switch } from "antd";

const { Panel } = Collapse;
const { Title, Paragraph, Text } = Typography;

// 错误边界包装器
function SafeDemo({ children }: { children: React.ReactNode }) {
  const [error, setError] = useState<null | Error>(null);
  const ref = useRef(children);
  // 只在初次渲染时捕获
  if (error) {
    return <div style={{ color: "red" }}>案例渲染出错：{error.message}</div>;
  }
  try {
    return <>{children}</>;
  } catch (e: any) {
    setError(e);
    return <div style={{ color: "red" }}>案例渲染出错：{e.message}</div>;
  }
}

// 1. useState
function UseStateDemo() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <Button onClick={() => setCount(count + 1)}>点击+1</Button>
      <span style={{ marginLeft: 8 }}>当前值: {count}</span>
    </div>
  );
}

// 2. useEffect
function UseEffectDemo() {
  const [msg, setMsg] = useState("还没触发");
  useEffect(() => {
    setMsg("useEffect 已触发");
  }, []);
  return <div>{msg}</div>;
}

// 3. useContext
const DemoContext = React.createContext("默认值");
function UseContextDemo() {
  return (
    <DemoContext.Provider value="Hello Context!">
      <Child />
    </DemoContext.Provider>
  );
  function Child() {
    const value = useContext(DemoContext);
    return <div>Context值: {value}</div>;
  }
}

// 4. useReducer
function reducer(state: { count: number }, action: { type: string }) {
  switch (action.type) {
    case "inc":
      return { count: state.count + 1 };
    default:
      return state;
  }
}
function UseReducerDemo() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <div>
      <Button onClick={() => dispatch({ type: "inc" })}>+1</Button>
      <span style={{ marginLeft: 8 }}>count: {state.count}</span>
    </div>
  );
}

// 5. useCallback
function UseCallbackDemo() {
  const [num, setNum] = useState(0);
  const memoizedFn = useCallback(() => num, [num]);
  return (
    <div>
      <Button onClick={() => setNum(num + 1)}>+1</Button>
      <span style={{ marginLeft: 8 }}>memoizedFn(): {memoizedFn()}</span>
    </div>
  );
}

// 6. useMemo
function UseMemoDemo() {
  const [a, setA] = useState(1);
  const double = useMemo(() => a * 2, [a]);
  return (
    <div>
      <Button onClick={() => setA(a + 1)}>+1</Button>
      <span style={{ marginLeft: 8 }}>a*2: {double}</span>
    </div>
  );
}

// 7. useRef
function UseRefDemo() {
  const inputRef = useRef<InputRef>(null);
  return (
    <div>
      <Input ref={inputRef} placeholder="点击按钮聚焦" style={{ width: 200 }} />
      <Button
        onClick={() => inputRef.current && inputRef.current.focus()}
        style={{ marginLeft: 8 }}
      >
        聚焦
      </Button>
    </div>
  );
}

// 8. useImperativeHandle
const ImperativeInput = React.forwardRef<InputRef, {}>((props, ref) => {
  const inputRef = useRef<InputRef>(null);
  useImperativeHandle(ref, () => inputRef.current as InputRef);
  return (
    <Input
      ref={inputRef}
      placeholder="父组件可调用 focus"
      style={{ width: 200 }}
    />
  );
});
function UseImperativeHandleDemo() {
  const ref = useRef<InputRef>(null);
  return (
    <div>
      <ImperativeInput ref={ref} />
      <Button
        onClick={() => ref.current && ref.current.focus()}
        style={{ marginLeft: 8 }}
      >
        父组件聚焦
      </Button>
    </div>
  );
}

// 9. useLayoutEffect
function UseLayoutEffectDemo() {
  const [width, setWidth] = useState(0);
  const divRef = useRef<HTMLDivElement>(null);
  useLayoutEffect(() => {
    if (divRef.current) setWidth(divRef.current.offsetWidth);
  });
  return <div ref={divRef}>div宽度: {width}</div>;
}

// 10. useDebugValue
function useCustomDebugValueDemo(val: number) {
  useDebugValue(val > 5 ? "大于5" : "小于等于5");
  return val;
}
function UseDebugValueDemo() {
  const [v, setV] = useState(0);
  useCustomDebugValueDemo(v);
  return <Button onClick={() => setV(v + 1)}>+1 (调试用)</Button>;
}

// 11. useDeferredValue (React 18)
function UseDeferredValueDemo() {
  const [value, setValue] = useState("");
  const deferredValue = useDeferredValue(value);
  return (
    <div>
      <Input
        value={value}
        onChange={(e) => setValue(e.target.value)}
        placeholder="输入内容"
        style={{ width: 200 }}
      />
      <div>deferredValue: {deferredValue}</div>
    </div>
  );
}

// 12. useTransition (React 18)
function UseTransitionDemo() {
  const [isPending, startTransition] = useTransition();
  const [text, setText] = useState("");
  return (
    <div>
      <Button
        onClick={() => {
          startTransition(() => {
            setText(Math.random().toString());
          });
        }}
      >
        startTransition
      </Button>
      <div>
        isPending: {isPending ? "是" : "否"}，text: {text}
      </div>
    </div>
  );
}

// 13. useId (React 18)
function UseIdDemo() {
  const id = useId();
  return (
    <div>
      useId 生成的唯一 id: <Text code>{id}</Text>
    </div>
  );
}

// 14. useSyncExternalStore (React 18)
function UseSyncExternalStoreDemo() {
  // 简单模拟 window resize 订阅
  const subscribe = (cb: () => void) => {
    window.addEventListener("resize", cb);
    return () => window.removeEventListener("resize", cb);
  };
  const getSnapshot = () => window.innerWidth;
  const width = useSyncExternalStore(subscribe, getSnapshot);
  return <div>window.innerWidth: {width}</div>;
}

// 15. useInsertionEffect (React 18)
function UseInsertionEffectDemo() {
  useInsertionEffect(() => {
    // 这里可以插入 CSS-in-JS 逻辑
  }, []);
  return <div>useInsertionEffect 用于 CSS-in-JS 场景</div>;
}

// 16. useOptimistic (React 19)
let useOptimisticDemo: any;
try {
  // React 19 新增
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  useOptimisticDemo = require("react").useOptimistic;
} catch {
  useOptimisticDemo = undefined;
}
function UseOptimisticDemo() {
  const [list, setList] = useState(["A", "B"]);
  // 仅在 React 19 可用
  if (!useOptimisticDemo) return <div>React 19 才支持 useOptimistic</div>;
  const [optimisticList, addOptimistic] = useOptimisticDemo(
    list,
    (state: string[], value: string) => [...state, value]
  );
  return (
    <div>
      <Button onClick={() => addOptimistic("C")}>乐观添加 C</Button>
      <div>乐观 UI: {optimisticList.join(", ")}</div>
    </div>
  );
}

// 17. use (React 18/19)
function UseDemo() {
  return <div>use 主要用于 Suspense 异步数据读取，React 19 正式支持</div>;
}

// 18. useFormStatus (React 19)
let useFormStatusDemo: any;
try {
  useFormStatusDemo = require("react").useFormStatus;
} catch {
  useFormStatusDemo = undefined;
}
function UseFormStatusDemo() {
  if (!useFormStatusDemo) return <div>React 19 才支持 useFormStatus</div>;
  function SubmitButton() {
    const status = useFormStatusDemo();
    return (
      <button type="submit" disabled={status.pending} style={{ marginLeft: 8 }}>
        {status.pending ? "提交中..." : "提交"}
      </button>
    );
  }
  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        setTimeout(() => alert("模拟提交完成"), 1000);
      }}
      style={{ display: "flex", alignItems: "center", gap: 8 }}
    >
      <input placeholder="输入内容" />
      <SubmitButton />
    </form>
  );
}

const hooksList = [
  {
    name: "useState",
    version: "16.8",
    desc: "组件状态管理。",
    demo: <UseStateDemo />,
  },
  {
    name: "useEffect",
    version: "16.8",
    desc: "副作用处理（如数据请求、订阅、手动 DOM 操作等）。",
    demo: <UseEffectDemo />,
  },
  {
    name: "useContext",
    version: "16.8",
    desc: "读取 React context 上下文。",
    demo: <UseContextDemo />,
  },
  {
    name: "useReducer",
    version: "16.8",
    desc: "更复杂的状态管理（类似 Redux reducer）。",
    demo: <UseReducerDemo />,
  },
  {
    name: "useCallback",
    version: "16.8",
    desc: "返回记忆化的回调函数，优化性能，避免不必要的子组件渲染。",
    demo: <UseCallbackDemo />,
  },
  {
    name: "useMemo",
    version: "16.8",
    desc: "返回记忆化的值，优化性能，避免重复计算。",
    demo: <UseMemoDemo />,
  },
  {
    name: "useRef",
    version: "16.8",
    desc: "获取/保存可变的引用值，常用于访问 DOM 或保存跨渲染周期的变量。",
    demo: <UseRefDemo />,
  },
  {
    name: "useImperativeHandle",
    version: "16.8",
    desc: "配合 forwardRef 自定义暴露给父组件的 ref 实例。",
    demo: <UseImperativeHandleDemo />,
  },
  {
    name: "useLayoutEffect",
    version: "16.8",
    desc: "类似 useEffect，但在 DOM 更新后同步执行。",
    demo: <UseLayoutEffectDemo />,
  },
  {
    name: "useDebugValue",
    version: "16.8",
    desc: "用于自定义 hook 的调试信息。",
    demo: <UseDebugValueDemo />,
  },
  {
    name: "useDeferredValue",
    version: "18.0",
    desc: "用于延迟渲染不重要的 UI，提高响应速度。",
    demo: <UseDeferredValueDemo />,
  },
  {
    name: "useTransition",
    version: "18.0",
    desc: "启用并发 UI 更新，标记某些更新为“可中断”。",
    demo: <UseTransitionDemo />,
  },
  {
    name: "useId",
    version: "18.0",
    desc: "生成唯一的、稳定的 ID，适合无障碍场景。",
    demo: <UseIdDemo />,
  },
  {
    name: "useSyncExternalStore",
    version: "18.0",
    desc: "用于订阅外部 store（如 Redux），保证并发安全。",
    demo: <UseSyncExternalStoreDemo />,
  },
  {
    name: "useInsertionEffect",
    version: "18.0",
    desc: "在 DOM 变更前同步执行，适合 CSS-in-JS 方案。",
    demo: <UseInsertionEffectDemo />,
  },
  {
    name: "useOptimistic",
    version: "19.0",
    desc: "用于实现乐观 UI 更新（React 19 新增）。",
    demo: <UseOptimisticDemo />,
  },
  {
    name: "useFormStatus",
    version: "19.0",
    desc: "用于表单内获取当前表单的提交状态（如是否正在提交），常用于按钮 loading/禁用等。React 19 新增。",
    demo: <UseFormStatusDemo />,
  },
  {
    name: "use",
    version: "18.0/19.0",
    desc: "用于读取异步资源（如 Suspense），React 18 实验，19 正式。",
    demo: <UseDemo />,
  },
];

export default function HooksPage() {
  return (
    <div style={{ maxWidth: 800, margin: "0 auto", padding: 24 }}>
      <Title level={2}>React 核心 Hooks 总结</Title>
      <Paragraph>
        <Text strong>
          每个 hooks 都标注了首次支持的 React 版本、作用说明，并有简单案例。
        </Text>
      </Paragraph>
      <Divider />
      <Collapse accordion>
        {hooksList.map((hook) => (
          <Panel
            header={
              <span>
                <Text code>{hook.name}</Text>
                <Text type="secondary" style={{ marginLeft: 8 }}>
                  v{hook.version}
                </Text>
              </span>
            }
            key={hook.name}
          >
            <Paragraph>
              <Text strong>作用：</Text>
              {hook.desc}
            </Paragraph>
            <Paragraph>
              <Text strong>案例：</Text>
            </Paragraph>
            <div style={{ marginBottom: 16 }}>
              <SafeDemo>{hook.demo}</SafeDemo>
            </div>
          </Panel>
        ))}
      </Collapse>
    </div>
  );
}
